package cloud.uke.jds.provider.mongodb;

import cloud.uke.jds.api.internal.InternalAbstractStoreDataHandler;
import cloud.uke.jds.api.internal.InternalWrapSyncData;
import java.time.LocalDateTime;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

/** @author du */
/**
 * MongoInternalStoreDataHandlerImpl class.
 *
 * @author du
 * @version $Id: $Id
 */
@Slf4j
public class MongoStoreDataHandlerImpl<T> extends InternalAbstractStoreDataHandler<T, ObjectId> {
  private final String collectionName;
  private final MongoTemplate mongoTemplate;

  /**
   * Constructor for MongoInternalStoreDataHandlerImpl.
   *
   * @param mongoTemplate a {@link org.springframework.data.mongodb.core.MongoTemplate} object
   * @param collectionName a {@link java.lang.String} object
   */
  public MongoStoreDataHandlerImpl(MongoTemplate mongoTemplate, String collectionName) {
    this.mongoTemplate = mongoTemplate;
    this.collectionName = collectionName;
  }

  /**
   * Constructor for MongoInternalStoreDataHandlerImpl.
   *
   * @param mongoTemplate a {@link org.springframework.data.mongodb.core.MongoTemplate} object
   */
  public MongoStoreDataHandlerImpl(MongoTemplate mongoTemplate) {
    this(mongoTemplate, null);
  }

  /** {@inheritDoc} */
  @Override
  public void save(T t) {
    MongoStoreData<T> data = new MongoStoreData<>(t);
    data.setSrc(src);
    if (collectionName == null || collectionName.isEmpty()) {
      mongoTemplate.save(data);
    } else {
      mongoTemplate.save(data, collectionName);
    }
  }

  /** {@inheritDoc} */
  @Override
  public InternalWrapSyncData<T, ObjectId> poll() {
    // 查询最后成功的一条记录id
    Query query = Query.query(Criteria.where("src").is(src).and("target").is(target));
    MongoSyncStatFlag statFlag = mongoTemplate.findOne(query, MongoSyncStatFlag.class);
    query = new Query().with(Sort.by(Direction.ASC, "_id"));

    if (statFlag != null) {
      if (statFlag.getLastId() == null) {
        log.warn("lastSuccessId in  is null, check program or mongo database of lastSuccessId");
        return null;
      }
      query.addCriteria(Criteria.where("_id").gt(statFlag.getLastId()));
    }

    @SuppressWarnings("unchecked")
    MongoStoreData<T> storeData = mongoTemplate.findOne(query, MongoStoreData.class);
    if (storeData == null) {
      return null;
    }

    InternalWrapSyncData<T, ObjectId> result = new InternalWrapSyncData<>();
    result.setData(storeData.getData());
    result.setLastSyncId(storeData.getId());
    result.setSrc(src);
    result.setTarget(target);
    return result;
  }

  /** {@inheritDoc} */
  @Override
  public void success(InternalWrapSyncData<T, ObjectId> data) {
    log.debug("处理成功，重置标志位: src: {},  target: {}, id: {}", src, target, data.getLastSyncId());
    Update update =
        new Update()
            .set("src", src)
            .set("target", target)
            .set("lastId", data.getLastSyncId())
            .set("updatedDate", LocalDateTime.now());
    Query query = Query.query(Criteria.where("src").is(src).and("target").is(target));
    mongoTemplate.upsert(query, update, MongoSyncStatFlag.class);
    if (syncBuilder.isAutoDelete()) {
      log.debug("删除记录： {}", data);
      mongoTemplate.remove(
          Query.query(Criteria.where("_id").is(data.getLastSyncId())), MongoStoreData.class);
    }
  }

  /** {@inheritDoc} */
  @Override
  public void reset() {
    log.warn("reset sync flag, src: {}, target: {}", src, target);
    Query query = Query.query(Criteria.where("src").is(src).and("target").is(target));
    mongoTemplate.remove(query, MongoSyncStatFlag.class);
  }

  /** {@inheritDoc} */
  @Override
  public void veryDangerOperationCleanAllData() {
    Query query = Query.query(Criteria.where("src").is(src));
    mongoTemplate.remove(query, MongoStoreData.class);
    reset();
  }
}
